<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>分片上传测试</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            max-width: 800px;
            margin: 0 auto;
            padding: 20px;
        }
        .container {
            border: 1px solid #ddd;
            border-radius: 8px;
            padding: 20px;
            margin-bottom: 20px;
        }
        .progress-bar {
            width: 100%;
            height: 20px;
            background-color: #f0f0f0;
            border-radius: 10px;
            overflow: hidden;
        }
        .progress-fill {
            height: 100%;
            background-color: #4CAF50;
            width: 0%;
            transition: width 0.3s;
        }
        button {
            background-color: #4CAF50;
            color: white;
            padding: 10px 20px;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            margin: 5px;
        }
        button:disabled {
            background-color: #cccccc;
            cursor: not-allowed;
        }
        button.cancel {
            background-color: #f44336;
        }
        .status {
            margin: 10px 0;
            padding: 10px;
            border-radius: 4px;
            background-color: #e0e0e0;
        }
        .status.success {
            background-color: #d4edda;
            color: #155724;
        }
        .status.error {
            background-color: #f8d7da;
            color: #721c24;
        }
        .status.info {
            background-color: #d1ecf1;
            color: #0c5460;
        }
        .file-info {
            background-color: #f8f9fa;
            padding: 15px;
            border-radius: 4px;
            margin: 10px 0;
        }
        .chunk-list {
            max-height: 200px;
            overflow-y: auto;
            border: 1px solid #ddd;
            padding: 10px;
            margin: 10px 0;
        }
    </style>
</head>
<body>
<h1>分片上传测试页面</h1>

<div class="container">
    <h2>后端配置</h2>
    <label for="backendUrl">后端服务器地址:</label>
    <input type="text" id="backendUrl" value="http://localhost:8080" style="width: 300px;">
</div>

<div class="container">
    <h2>文件选择</h2>
    <input type="file" id="fileInput" accept="video/*" />
    <button id="selectFileBtn">选择文件</button>
    <div id="fileInfo" class="file-info" style="display: none;"></div>
</div>

<div class="container">
    <h2>上传控制</h2>
    <button id="startUploadBtn" disabled>开始上传</button>
    <button id="pauseUploadBtn" disabled>暂停上传</button>
    <button id="resumeUploadBtn" disabled>继续上传</button>
    <button id="cancelUploadBtn" class="cancel" disabled>取消上传</button>

    <div class="progress-bar">
        <div id="progressFill" class="progress-fill"></div>
    </div>
    <div id="progressText">进度: 0%</div>
</div>

<div class="container">
    <h2>上传状态</h2>
    <div id="status" class="status">请选择文件开始上传</div>
</div>

<div class="container">
    <h2>已上传分片</h2>
    <button id="refreshChunksBtn" disabled>刷新分片列表</button>
    <div id="chunkList" class="chunk-list">暂无分片信息</div>
</div>

<script>
    // 全局变量
    let currentFile = null;
    let taskId = '';
    let uploadedChunks = new Set();
    let totalChunks = 0;
    let chunkSize = 5 * 1024 * 1024; // 5MB
    let currentChunk = 0;
    let isUploading = false;
    let isPaused = false;

    // DOM 元素
    const backendUrlInput = document.getElementById('backendUrl');
    const fileInput = document.getElementById('fileInput');
    const selectFileBtn = document.getElementById('selectFileBtn');
    const fileInfo = document.getElementById('fileInfo');
    const startUploadBtn = document.getElementById('startUploadBtn');
    const pauseUploadBtn = document.getElementById('pauseUploadBtn');
    const resumeUploadBtn = document.getElementById('resumeUploadBtn');
    const cancelUploadBtn = document.getElementById('cancelUploadBtn');
    const refreshChunksBtn = document.getElementById('refreshChunksBtn');
    const progressFill = document.getElementById('progressFill');
    const progressText = document.getElementById('progressText');
    const status = document.getElementById('status');
    const chunkList = document.getElementById('chunkList');

    // 事件监听器
    selectFileBtn.addEventListener('click', () => fileInput.click());
    fileInput.addEventListener('change', handleFileSelect);
    startUploadBtn.addEventListener('click', startUpload);
    pauseUploadBtn.addEventListener('click', pauseUpload);
    resumeUploadBtn.addEventListener('click', resumeUpload);
    cancelUploadBtn.addEventListener('click', cancelUpload);
    refreshChunksBtn.addEventListener('click', refreshChunkList);

    // 获取后端API基础URL
    function getApiBaseUrl() {
        const backendUrl = backendUrlInput.value.trim();
        if (!backendUrl) {
            return 'http://localhost:8080';
        }
        // 确保URL末尾没有斜杠
        return backendUrl.endsWith('/') ? backendUrl.slice(0, -1) : backendUrl;
    }

    // 处理文件选择
    function handleFileSelect(event) {
        const file = event.target.files[0];
        if (!file) return;

        currentFile = file;
        taskId = 'task_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
        showFileInfo(file);
        startUploadBtn.disabled = false;
        refreshChunksBtn.disabled = false;
        updateStatus('文件已选择，点击开始上传按钮进行分片上传', 'info');
    }

    // 显示文件信息
    function showFileInfo(file) {
        fileInfo.style.display = 'block';
        totalChunks = Math.ceil(file.size / chunkSize);

        fileInfo.innerHTML = `
                <strong>文件名:</strong> ${file.name}<br>
                <strong>文件大小:</strong> ${formatFileSize(file.size)}<br>
                <strong>分片大小:</strong> ${formatFileSize(chunkSize)}<br>
                <strong>总分片数:</strong> ${totalChunks}<br>
                <strong>任务ID:</strong> ${taskId}
            `;
    }

    // 格式化文件大小
    function formatFileSize(bytes) {
        if (bytes === 0) return '0 B';
        const k = 1024;
        const sizes = ['B', 'KB', 'MB', 'GB'];
        const i = Math.floor(Math.log(bytes) / Math.log(k));
        return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
    }

    // 更新状态显示
    function updateStatus(message, type = '') {
        status.textContent = message;
        status.className = 'status ' + type;
    }

    // 更新进度显示
    function updateProgress(percent) {
        progressFill.style.width = percent + '%';
        progressText.textContent = `进度: ${percent.toFixed(2)}%`;
    }

    // 初始化上传任务
    async function initUpload() {
        try {
            updateStatus('正在初始化上传任务...', 'info');

            // 模拟文件MD5 (实际应用中应该计算真实MD5)
            const fileMd5 = 'md5_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);

            const response = await fetch(`${getApiBaseUrl()}/api/direct-upload/init`, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify({
                    taskId: taskId,
                    fileName: currentFile.name,
                    fileSize: currentFile.size,
                    fileMd5: fileMd5,
                    chunkSize: chunkSize,
                    totalChunks: totalChunks
                })
            });

            if (!response.ok) {
                throw new Error('初始化上传任务失败: ' + response.statusText);
            }

            const result = await response.json();
            updateStatus('上传任务初始化成功', 'success');
            return result;
        } catch (error) {
            updateStatus('初始化上传任务失败: ' + error.message, 'error');
            throw error;
        }
    }

    // 获取已上传分片列表
    async function getUploadedChunks() {
        try {
            const response = await fetch(`${getApiBaseUrl()}/api/direct-upload/chunks/${taskId}`);
            if (!response.ok) {
                throw new Error('获取已上传分片列表失败: ' + response.statusText);
            }

            const result = await response.json();
            uploadedChunks = new Set(result.data || []);
            displayChunkList();
            return uploadedChunks;
        } catch (error) {
            updateStatus('获取已上传分片列表失败: ' + error.message, 'error');
            return new Set();
        }
    }

    // 刷新分片列表显示
    async function refreshChunkList() {
        if (!taskId) {
            updateStatus('请先选择文件', 'error');
            return;
        }

        await getUploadedChunks();
        updateStatus(`已刷新分片列表，已上传 ${uploadedChunks.size} 个分片`, 'info');
    }

    // 显示分片列表
    function displayChunkList() {
        if (uploadedChunks.size === 0) {
            chunkList.innerHTML = '暂无已上传分片';
            return;
        }

        const chunks = Array.from(uploadedChunks).sort((a, b) => a - b);
        chunkList.innerHTML = `
                <p>已上传分片: ${chunks.length}/${totalChunks}</p>
                <p>分片序号: ${chunks.join(', ')}</p>
            `;
    }

    // 上传单个分片
    async function uploadChunk(chunkNumber) {
        return new Promise((resolve, reject) => {
            const start = chunkNumber * chunkSize;
            const end = Math.min(start + chunkSize, currentFile.size);
            const chunk = currentFile.slice(start, end);

            const formData = new FormData();
            formData.append('taskId', taskId);
            formData.append('chunkNumber', chunkNumber.toString());
            formData.append('chunk', chunk);
            formData.append('chunkSize', chunkSize.toString());
            formData.append('currentChunkSize', (end - start).toString());

            const xhr = new XMLHttpRequest();

            xhr.upload.addEventListener('progress', (e) => {
                if (e.lengthComputable) {
                    const chunkProgress = (e.loaded / e.total) * 100;
                    const overallProgress = ((chunkNumber + chunkProgress / 100) / totalChunks) * 100;
                    updateProgress(overallProgress);
                }
            });

            xhr.addEventListener('load', () => {
                if (xhr.status >= 200 && xhr.status < 300) {
                    resolve(JSON.parse(xhr.responseText));
                } else {
                    reject(new Error('上传分片失败: ' + xhr.statusText));
                }
            });

            xhr.addEventListener('error', () => {
                reject(new Error('网络错误'));
            });

            xhr.open('POST', `${getApiBaseUrl()}/api/direct-upload/chunk`);
            xhr.send(formData);
        });
    }

    // 完成上传
    async function completeUpload() {
        try {
            updateStatus('已经完成上传', 'info');

            const response = await fetch(`${getApiBaseUrl()}/api/direct-upload/complete`, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify({
                    taskId: taskId,
                    fileName: currentFile.name,
                    fileSize: currentFile.size
                })
            });

            if (!response.ok) {
                throw new Error('完成上传失败: ' + response.statusText);
            }

            const result = await response.json();
            updateStatus('上传完成!', 'success');
            return result;
        } catch (error) {
            updateStatus('完成上传失败: ' + error.message, 'error');
            throw error;
        }
    }

    // 开始上传
    async function startUpload() {
        if (!currentFile) {
            updateStatus('请先选择文件', 'error');
            return;
        }

        if (isUploading) {
            updateStatus('上传已在进行中', 'error');
            return;
        }

        try {
            isUploading = true;
            isPaused = false;
            startUploadBtn.disabled = true;
            pauseUploadBtn.disabled = false;
            cancelUploadBtn.disabled = false;

            // 初始化上传任务
            await initUpload();

            // 获取已上传分片
            await getUploadedChunks();

            // 逐个上传分片
            for (let i = 0; i < totalChunks; i++) {
                // 检查是否需要暂停
                while (isPaused) {
                    await new Promise(resolve => setTimeout(resolve, 100));
                }

                // 检查是否已取消
                if (!isUploading) {
                    return;
                }

                // 跳过已上传的分片
                if (uploadedChunks.has(i)) {
                    const progress = ((i + 1) / totalChunks) * 100;
                    updateProgress(progress);
                    updateStatus(`跳过分片 ${i + 1}/${totalChunks} (已上传)`, 'info');
                    continue;
                }

                // 上传当前分片
                updateStatus(`正在上传分片 ${i + 1}/${totalChunks}...`, 'info');
                await uploadChunk(i);
                uploadedChunks.add(i);

                // 更新进度
                const progress = ((i + 1) / totalChunks) * 100;
                updateProgress(progress);
                displayChunkList();
            }

            // 完成上传
            const result = await completeUpload();
            updateStatus(`上传成功! 视频ID: ${result.data.id}`, 'success');

            // 重置状态
            resetUploadState();

        } catch (error) {
            updateStatus('上传失败: ' + error.message, 'error');
            isUploading = false;
        }
    }

    // 暂停上传
    function pauseUpload() {
        if (!isUploading) {
            updateStatus('没有正在进行的上传任务', 'error');
            return;
        }

        isPaused = true;
        pauseUploadBtn.disabled = true;
        resumeUploadBtn.disabled = false;
        updateStatus('上传已暂停', 'info');
    }

    // 继续上传
    function resumeUpload() {
        if (!isUploading) {
            updateStatus('没有暂停的上传任务', 'error');
            return;
        }

        isPaused = false;
        pauseUploadBtn.disabled = false;
        resumeUploadBtn.disabled = true;
        updateStatus('继续上传...', 'info');
    }

    // 取消上传
    function cancelUpload() {
        isUploading = false;
        isPaused = false;
        resetUploadState();
        updateStatus('上传已取消', 'info');
    }

    // 重置上传状态
    function resetUploadState() {
        isUploading = false;
        isPaused = false;
        startUploadBtn.disabled = false;
        pauseUploadBtn.disabled = true;
        resumeUploadBtn.disabled = true;
        cancelUploadBtn.disabled = true;
    }
</script>
</body>
</html>
